import os
import re
import shutil
import traceback
from os.path import exists

import wx
from loguru import logger

from Beremiz.LogPseudoFile import LogPseudoFile
from Beremiz.controls.CustomStyledTextCtrl import CustomStyledTextCtrl
from backend.disk import usbpath

_ = wx.GetTranslation
if wx.Platform == '__WXMSW__':
    faces = {
        'mono': 'Courier New',
        'size': 8,
    }
else:
    faces = {
        'mono': 'Courier',
        'size': 10,
    }


def purge(dir, pattern):
    for f in os.listdir(dir):
        if re.search(pattern, f):
            os.remove(os.path.join(dir, f))


class UCopyEditor(wx.Dialog):
    def _init_ctrls(self, parent):
        self.UriTypeChoice = wx.Choice(parent=self, choices=self.choices, size=wx.Size(200, 32))
        self.UriTypeChoice.SetSelection(0)
        self.Bind(wx.EVT_CHOICE, self.OnTypeChoice, self.UriTypeChoice)
        self.editor_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.LogConsole = CustomStyledTextCtrl(name='LogConsole', parent=self, size=wx.Size(400, 200))
        self.LogConsole.SetReadOnly(True)
        self.LogConsole.SetWrapMode(wx.stc.STC_WRAP_CHAR)

        # Define Log Console styles
        self.LogConsole.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
        self.LogConsole.StyleClearAll()
        self.LogConsole.StyleSetSpec(1, "face:%(mono)s,fore:#FF0000,size:%(size)d" % faces)
        self.LogConsole.StyleSetSpec(2, "face:%(mono)s,fore:#FF0000,back:#FFFF00,size:%(size)d" % faces)

        # Define Log Console markers
        self.LogConsole.SetMarginSensitive(1, True)
        self.LogConsole.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL)
        self.LogConsole.MarkerDefine(0, wx.stc.STC_MARK_CIRCLE, "BLACK", "RED")

        self.LogConsole.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT)

        self.ButtonSizer = self.CreateButtonSizer(wx.CANCEL)

        self.ButtonFlash = wx.Button(self, -1, _('Copy'))
        self.ButtonFlash.Bind(wx.EVT_BUTTON, self.flash)
        self.ButtonTo = wx.Button(self, -1, _('Copy to'))
        self.ButtonTo.Bind(wx.EVT_BUTTON, self.copyto)
        self.prgRte = wx.CheckBox(self, label=_("复制RTE固件"))
        self.prgApp = wx.CheckBox(self, label=_("复制PLC程序"))
        self.prgBoot = wx.CheckBox(self, label="复制bootloader")
        self.prgRte.SetValue(True)
        self.prgApp.SetValue(True)
        self.prgBoot.SetValue(False)

    def _init_sizers(self):
        self.mainSizer = wx.BoxSizer(wx.VERTICAL)
        typeSizer = wx.BoxSizer(wx.HORIZONTAL)
        typeSizer.Add(wx.StaticText(self, wx.ID_ANY, _("disk :")), border=5,
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
        typeSizer.Add(self.UriTypeChoice, border=5, flag=wx.EXPAND | wx.ALL)
        self.mainSizer.Add(typeSizer, border=5, flag=wx.EXPAND | wx.ALL)

        optionSizer = wx.BoxSizer(wx.VERTICAL)
        optionSizer.Add(self.prgRte)
        optionSizer.Add(self.prgApp)
        optionSizer.Add(self.prgBoot)
        self.mainSizer.Add(optionSizer, border=5, flag=wx.ALL)

        self.mainSizer.Add(self.editor_sizer, border=5, flag=wx.ALL)
        self.mainSizer.Add(self.LogConsole, border=5, flag=wx.EXPAND | wx.ALL, )
        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
        buttonSizer.Add(self.ButtonFlash, border=5,
                        flag=wx.BOTTOM)
        buttonSizer.Add(self.ButtonTo, border=5, flag=wx.BOTTOM)
        buttonSizer.Add(self.ButtonSizer, border=5,
                        flag=wx.BOTTOM)
        self.mainSizer.Add(buttonSizer, border=5, flag=wx.ALL)
        self.SetSizer(self.mainSizer)
        self.Layout()
        self.Fit()

    def __init__(self, parent, ctr):
        wx.Dialog.__init__(self, name='UCopyEditor', parent=parent, title=_('Copy Firmware to UDisk'))
        self.ctr = ctr
        self.choices = []
        self._init_ctrls(parent)
        self._init_sizers()
        self.CenterOnParent()
        self.Log = LogPseudoFile(self.LogConsole, self.output, None)
        # self.Log = LogViewer(self.LogConsole, self)
        # self.LogConsole.SetLogSource(logging)
        self.verify = False

        # return
        self.CenterOnParent()
        self.tmr = wx.Timer(parent, -1)
        parent.Bind(wx.EVT_TIMER, self.onTmr, self.tmr)
        self.tmr.Start(1000)
        try:
            app_path = os.getcwd()
            board = self.ctr.GetChildByName('board_0')
            if not board:
                dialog = wx.MessageDialog(parent, _('Can not Found "board_0",Please attach one board.'),
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            node = board.board_class
            self.model = node.custom_model or node.model
            self.dev_id = node.dev_id
            builder = self.ctr.GetBuilder()
            self.appBin = builder.GetBinaryPath()

            rte = board.current_rte
            if not rte.current_ver:
                dialog = wx.MessageDialog(parent, '未选择使用的RTE固件,请检查board配置.',
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            self.rtebin = os.path.join(rte.path, "rte.bin")
            if not exists(self.rtebin):
                dialog = wx.MessageDialog(parent, _("Cannot Get RTE bin."), style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
            self.rte_txt = 'rte.bin-' + rte.current_ver['version']
            if not exists(self.appBin):
                dialog = wx.MessageDialog(parent, _("Cannot Get PLC Firmware.Please Exec Build."),
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
            boot = board.current_boot
            if exists(os.path.join(boot.path, "rte.bin")):
                self.bootbin = os.path.join(boot.path, "rte.bin")
            elif exists(boot.path + ".bin"):
                self.bootbin = boot.path + ".bin"
            self.boot_txt = 'bootloader.bin-' + boot.current_ver['version']
            contentHeader = self.ctr.Project.getcontentHeader()
            name = contentHeader.get('projectName')
            version = contentHeader.get('projectVersion') or '0'
            self.plc_txt = 'plc.bin-' + name + '-' + version + '-' + str(builder.GetBuildNumber())
        except Exception as ex:
            logger.debug(traceback.format_exc())
            dialog = wx.MessageDialog(parent, str(ex), style=wx.YES_DEFAULT | wx.CENTRE)
            dialog.ShowModal()
            wx.CallAfter(self.Close)

    def onTmr(self, event):
        choices = usbpath()
        if choices != self.choices:
            self.choices = choices
            strList = [x[1] for x in choices]
            self.UriTypeChoice.SetItems(strList)
            if len(choices) == 1:
                self.UriTypeChoice.SetSelection(0)
        if self.UriTypeChoice.GetSelection() >= 0 and (self.prgApp.IsChecked() or self.prgRte.IsChecked()):
            self.ButtonFlash.Enable()
        else:
            self.ButtonFlash.Disable()
        event.Skip()

    def OnTypeChoice(self, event):
        index = event.GetSelection()
        self.udrive = self.choices[index]

    def copyto(self, event):
        dialog = wx.DirDialog(self, _("Choose an empty directory for file save"), '.')
        if dialog.ShowModal() == wx.ID_OK:
            path = dialog.GetPath()
            self.Log.flush()
            self.Log.write(_('Copy firmware to %s') % path)
            rte = os.path.join(path, 'rte.bin')
            if self.prgRte.IsChecked():
                purge(path, "rte.bin*")
                shutil.copy(self.rtebin, rte)
                with open(os.path.join(path, self.rte_txt), 'w') as f:
                    f.write(self.rte_txt)
                self.Log.write('RTE固件已复制.')
            elif exists(rte):
                purge(path, "rte.bin*")
                self.Log.write('从U盘删除了RTE固件.')

            app = os.path.join(path, 'plc.bin')
            if self.prgApp.IsChecked():
                purge(path, "plc.bin*")
                shutil.copy(self.appBin, app)
                with open(os.path.join(path, self.plc_txt), 'w') as f:
                    f.write(self.plc_txt)
                self.Log.write('PLC程序已复制.')
            elif exists(app):
                purge(path, "plc.bin*")
                self.Log.write('从U盘删除了PLC程序.')
            boot = os.path.join(path, 'bootloader.bin')
            if self.prgBoot.IsChecked():
                purge(path, "bootloader.bin*")
                shutil.copy(self.bootbin, boot)
                with open(os.path.join(path, self.boot_txt), 'w') as f:
                    f.write(self.boot_txt)
                self.Log.write('BootLoader已复制.')
            elif exists(boot):
                purge(path, "bootloader.bin*")
                self.Log.write('从U盘删除了bootloader文件')
            self.Log.write('复制完成.')

    def flash(self, event):
        self.Log.flush()
        index = self.UriTypeChoice.GetSelection()
        udisk = self.choices[index][0]
        self.udrive = self.choices[index]
        self.Log.write(_('Copy firmware to UDisk %s') % udisk)
        rte = os.path.join(udisk, 'rte.bin')
        if self.prgRte.IsChecked():
            purge(udisk, "rte.bin*")
            shutil.copy(self.rtebin, rte)
            with open(os.path.join(udisk, self.rte_txt), 'w') as f:
                f.write(self.rte_txt)
            self.Log.write('RTE固件已复制.')
        elif exists(rte):
            purge(udisk, "rte.bin*")
            self.Log.write('从U盘删除了RTE固件.')

        app = os.path.join(udisk, 'plc.bin')
        if self.prgApp.IsChecked():
            purge(udisk, "plc.bin*")
            shutil.copy(self.appBin, app)
            with open(os.path.join(udisk, self.plc_txt), 'w') as f:
                f.write(self.plc_txt)
            self.Log.write('PLC程序已复制.')
        elif exists(app):
            purge(udisk, "plc.bin*")
            self.Log.write('从U盘删除了PLC程序.')

        boot = os.path.join(udisk, 'bootloader.bin')
        if self.prgBoot.IsChecked():
            purge(udisk, "bootloader.bin*")
            shutil.copy(self.bootbin, boot)
            with open(os.path.join(udisk, self.boot_txt), 'w') as f:
                f.write(self.boot_txt)
            self.Log.write('BootLoader已复制.')
        elif exists(boot):
            purge(udisk, "bootloader.bin*")
            self.Log.write('从U盘删除了bootloader文件')
        self.Log.write('复制完成.')

    def output(self, txt):
        pass
        # self.LogConsole.AppendText(txt)
